﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Security.Cryptography;
using System.Collections;

namespace StationUpdate
{
    public class SocketHealper
    {
        #region 构造函数及私有成员
        /// <summary>
        /// 网络端点
        /// </summary>
        private IPEndPoint _ipRemotePoint;
        /// <summary>
        /// 客户端Socket对象
        /// </summary>
        private static Socket _socketClient;
        /// <summary>
        /// 客户端SocketHealper对象
        /// </summary>
        private static SocketHealper _socketHealper;

        private SocketHealper() 
        {
        }
        #endregion
        #region 开放成员
        /// <summary>
        /// 读取数据等待时间 默认10毫秒，在10毫秒内一直读取直到网络上有数据
        /// </summary>
        public const int ReadTime = 60;
        /// <summary>
        /// IP
        /// </summary>
        public string SocketIP = "";
        /// <summary>
        /// 端口
        /// </summary>
        public int SocketPort = 0;
        /// <summary>
        /// 设置发送超时时间，单位秒
        /// </summary>
        public int SendTimeout;
        /// <summary>
        /// 接收超时间，单位秒
        /// </summary>
        public int ReceiveTimeout;
        
        #endregion 
        private void InitSocket()
        {
            this._ipRemotePoint = new IPEndPoint(IPAddress.Parse(SocketIP), SocketPort);
            _socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //设置发送超时时间
            _socketClient.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, SendTimeout*1000);
            _socketClient.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, ReceiveTimeout*1000);
        }

        #region 单例创建socketClient
        /// <summary>
        /// 创建socketClient
        /// </summary>
        /// <returns></returns>
        public static SocketHealper CreateIntance() 
        {
            object synRoot = new object();
            if (_socketHealper == null) 
            {
                lock (synRoot) 
                {
                    if (_socketHealper == null) 
                    {
                        _socketHealper = new SocketHealper();
                    }
                }
            }
            return _socketHealper;
        }
        #endregion
        
        #region 连接服务器
        /// <summary>
        /// 测试网络及SOCKET是否通
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="msgCode">
        /// -1：socket连接失败，同时网络连接失败；
        /// -2：网络可以PING通，但SOCKET连接失败；
        /// 100：SOCKET连接成功；
        /// 101：SOCKET处理连接成功状态
        /// </param>
        /// <returns></returns>
        public bool Connect(ref string msg, ref int msgCode) 
        {
            try 
            {
                if (_socketClient != null && _socketClient.Connected == true)
                {
                    msg = "socket处于连接状态";
                    msgCode = 101;
                    return true;
                }
                try
                {
                    Close();
                    InitSocket();
                    _socketClient.Connect(this._ipRemotePoint);
                }
                catch (Exception ex) 
                {
                    Close();
                    //重新创建SOCKET
                    InitSocket();
                    _socketClient.Connect(this._ipRemotePoint);
                }

                if (!_socketClient.Connected)
                {
                    msg = "连接socket连接失败。";
                    msgCode = -1;
                    Close();
                    if (Ping.PingHost(SocketIP))
                    {
                        msg = "网络可以PING通，但SOCKET连接失败。";
                        msgCode = -2;
                    }
                    return false;
                }
                msg= "连接socket连接成功。";
                msgCode = 100;
                return true;
            }
            catch (SocketException se)
            {
                msgCode = -1;
                Close();
                if (Ping.PingHost(SocketIP))
                {
                    msg = "网络可以PING通，但SOCKET发生异常：" + se.Message;
                    msgCode = -2;
                }
                else 
                {
                    msg = "网络不可以PING通，SOCKET尝试连接时发生异常：" + se.Message;
                    msgCode = -1;
                }
                return false;
            }
        }
        #endregion
        /// <summary>
        /// 释放SOCKET
        /// </summary>
        public void Close() 
        {
            try
            {
                //释放原来socket
                if (_socketClient != null)
                {
                    _socketClient.Shutdown(SocketShutdown.Both);
                    _socketClient.Close();
                    _socketClient.Dispose();

                }
            }
            catch (Exception ex) 
            { }
        }

        #region 其它相关方法
        private static Encoding mChineseEncoding = Encoding.GetEncoding("GBK");
        private static Encoding mDeafultEncoding = Encoding.ASCII;
        
        /// <summary>
        /// 字符串MD5加密
        /// </summary>
        /// <param name="strText">输入字符串</param>
        /// <returns>已经加密的字符串,全部小写</returns>
        private static string MD5Encrypt(string strText)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] result = md5.ComputeHash(System.Text.Encoding.ASCII.GetBytes(strText));
            return BitConverter.ToString(result, 0).Replace("-", "").ToLower();
        }

        /// <summary>
        /// 将int数据转换为Byte数组
        /// </summary>
        /// <param name="mValue"></param>
        /// <returns></returns>
        private static byte[] ToBytes(uint mValue)
        {
            byte[] mBytes = BitConverter.GetBytes(mValue);
            return mBytes;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="mValue"></param>
        /// <param name="mOLength">指定返回数据长度</param>
        /// <returns></returns>
        private static byte[] ToBytes(String mValue, int mOLength)
        {
            byte[] mBytes = new byte[mOLength];
            byte[] mTempBytes = mDeafultEncoding.GetBytes(mValue);
            if (mTempBytes.Length >= mOLength)
            {
                Array.Copy(mTempBytes, 0, mBytes, 0, mOLength);
            }
            else
            {
                Array.Copy(mTempBytes, 0, mBytes, 0, mTempBytes.Length);
                for (int i = mTempBytes.Length; i < mOLength; i++)
                {
                    mBytes[i] = (byte)' ';
                }
            }
            return mBytes;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="mValue"></param>
        /// <param name="mOLength">指定返回数据长度</param>
        /// <returns></returns>
        private static byte[] ToChineseBytes(String mValue, int mOLength)
        {
            byte[] mBytes = new byte[mOLength];
            byte[] mTempBytes = mChineseEncoding.GetBytes(mValue);
            if (mTempBytes.Length >= mOLength)
            {
                Array.Copy(mTempBytes, 0, mBytes, 0, mOLength);
            }
            else
            {
                Array.Copy(mTempBytes, 0, mBytes, 0, mTempBytes.Length);
                for (int i = mTempBytes.Length; i < mOLength; i++)
                {
                    mBytes[i] = (byte)' ';
                }
            }
            return mBytes;
        }

        /// <summary>
        /// 返回字符串转换成byte后的长度
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public int stringToByteLen(string str)
        {
            return Encoding.Default.GetBytes(str).Length;
        }
        /// <summary>
        /// 获取返回字符中特定位置的字符串
        /// </summary>
        /// <param name="buff">字符数据组</param>
        /// <param name="istartpos">开始位置</param>
        /// <param name="length">长度</param>
        /// <returns></returns>
        private string GetReciveDataString(Byte[] buff, int istartpos, int length)
        {
            return Encoding.Default.GetString(buff, istartpos, length);
        }
        /// <summary>
        /// 字符串转换成byte数组
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public byte[] StringToByte(string str)
        {
            return Encoding.Default.GetBytes(str);
        }
        /// <summary>
        /// byte数组转换成字符串
        /// </summary>
        /// <param name="bt"></param>
        /// <returns></returns>
        public string ByteToString(byte[] bt, int index, int count)
        {
            return System.Text.Encoding.Default.GetString(bt, index, count);
        }
        #endregion

        #region 发送数据包
        /// <summary>
        /// 发送数据包
        /// 写之前要先清除接收缓冲区
        /// </summary>
        /// <param name="buf"></param>
        /// <returns></returns>
        public int Send(byte[] buf, ref string msg)
        {
            int write = 0;
            try
            {
                //{
                    //如果网络上有数据,先清除缓冲区剩余无效数据
                    //if (_socketClient.Available > 0)
                    //{
                    //    byte[] _recvBuf = new byte[1024];
                    //    int read = _socketClient.Receive(_recvBuf);//,0,buf.Length ,SocketFlags .None ); 
                    //}
                    //pool 单位是微秒 ,等待10毫秒
                    if (_socketClient.Poll(1000 * ReadTime, System.Net.Sockets.SelectMode.SelectWrite))
                    {
                        write = _socketClient.Send(buf);//,0,buf.Length ,SocketFlags.None);
                        
                    }
                //}
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return write;
        }
        #endregion

        //#region 接收数据包
        ///// <summary>
        ///// 接收数据包
        ///// </summary>
        ///// <returns></returns>
        //public int Receive(ref byte[] buf)
        //{
        //    object synRoot = new object();
        //    int read = 0;
        //    try
        //    {
        //        //等待下
        //        Thread.Sleep(ParaInfo.WaitTime * 1000);

        //        //pool 单位是微秒
        //        if (Connect() && _socketClient.Poll(1000 * ReadTime, System.Net.Sockets.SelectMode.SelectRead))
        //        {
        //            //如果网络上有数据
        //            if (_socketClient.Available > 0)
        //            {
        //                read = _socketClient.Receive(buf);

        //                //读取完成，更新最后一次与服务器的交互时间
        //                if (read > 0)
        //                {
        //                    lock (synRoot)
        //                    {
        //                        ParaInfo.LastTime = DateTime.Now;
        //                    }
        //                }
        //            }
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        throw ex;
        //    }
        //    return read;
        //}
        //#endregion


        #region 接收数据包
        /// <summary>
        /// 接收数据包
        /// </summary>
        /// <returns></returns>
        public byte[] Receive(ref int receiveLength, ref string msg)
        {
            int read = 0;
            byte[] retByte = null;

            List<byte[]> list = new List<byte[]>();
            try
            {
                //等待下
                //Thread.Sleep(ParaInfo.WaitTime * 1000);

                //pool 单位是微秒
                //if (Connect(ref msg) /*&& _socketClient.Poll(1000 * ReadTime, System.Net.Sockets.SelectMode.SelectRead)*/)
                //{
                    //如果网络上有数据 _socketClient.Available
                    while (_socketClient.Available > 0) 
                    {
                        byte[] bufTmp = new byte[1024];
                        read = _socketClient.Receive(bufTmp, bufTmp.Length, SocketFlags.None);
                        list.Add(bufTmp);
                        Thread.Sleep(10);
                        receiveLength = receiveLength + read;
                    }

                    if (receiveLength <= 0)
                    {
                        //没收到数据
                        return null;
                    }

                    retByte = new byte[receiveLength];
                    byte[] retTmpByte = new byte[list.Count * 1024];
                    #region 将list数据转移致buf中
                    int curRead = 0;
                    for (int i = 0; i < list.Count; i++)
                    {
                        Buffer.BlockCopy(list[i], 0, retTmpByte, curRead, list[0].Length);
                        curRead = curRead + list[i].Length;
                    }

                    Buffer.BlockCopy(retTmpByte, 0, retByte, 0, receiveLength);


                    #endregion
                //}
            }
            catch (Exception ex)
            {

                throw ex;
            }
            return retByte;
        }
        #endregion
    }
}
